# coding:utf-8
'''
Created on 2010-1-7

@author: Jason Green
@author-email: guileen@gmail.com
'''
from django.views.generic import list_detail, create_update
from django.contrib.contenttypes.models import ContentType
from django.http import Http404, HttpResponseRedirect, HttpResponse, QueryDict
from django.template import loader
from django.template import TemplateDoesNotExist
from django.contrib.auth.views import redirect_to_login
from django.utils.translation import ugettext
from django.contrib import messages
from django.core.exceptions import ImproperlyConfigured
from django.template.context import RequestContext
from jinja2.exceptions import TemplateNotFound
from django.views.decorators.cache import never_cache

USE_DEFAULT_PERMISSION = 'USE_DEFAULT_PERMISSION'

def get_model_calss(app_label, model):
    try:
        return ContentType.objects.get(app_label=app_label, model=model).model_class()
    except:
        raise Http404('no content of applabel=<%s> model=<%s> found' % (app_label, model))

def get_queryset(app_label, model):
    return get_model_calss(app_label, model).objects.all()

def get_object(app_label, model, object_id):
    return get_model_calss(app_label, model).objects.get(object_id)

def select_template_name(*args):
    for template_name in args:
        try:
            loader.get_template(template_name)
            return template_name
        except TemplateDoesNotExist:
            continue
        except TemplateNotFound:
            continue
    # If we get here, none of the templates could be loaded
    raise TemplateNotFound, ', '.join(args)

def select_generic_template_name(app_label, model, suffix):
    return select_template_name('/%s/%s_%s.html' % (app_label, model, suffix), '/generic/object_%s.html' % suffix)

def select_generic_template(app_label, model, suffix):
    return loader.select_template(('/%s/%s_%s.html' % (app_label, model, suffix), '/generic/object_%s.html' % suffix,))

def redirect(post_save_redirect, obj, app_label=None, model=None):
    """
    Returns a HttpResponseRedirect to ``post_save_redirect``.

    ``post_save_redirect`` should be a string, and can contain named string-
    substitution place holders of ``obj`` field names.

    If ``post_save_redirect`` is None, then redirect to ``obj``'s URL returned
    by ``get_absolute_url()``.  If ``obj`` has no ``get_absolute_url`` method,
    then raise ImproperlyConfigured.

    This function is meant to handle the post_save_redirect parameter to the
    ``create_object`` and ``update_object`` views.
    """
    if post_save_redirect:
        return HttpResponseRedirect(post_save_redirect % obj.__dict__)
    elif hasattr(obj, 'get_absolute_url'):
        return HttpResponseRedirect(obj.get_absolute_url())
    elif app_label and model:
        return HttpResponseRedirect('/%s/%s/%d/' % (app_label, model, obj.id))
    else:
        raise ImproperlyConfigured(
            "No URL to redirect to.  Either pass a post_save_redirect"
            " parameter to the generic view or define a get_absolute_url"
            " method on the Model.")

def object_list(request, app_label, model, query_set=None):
    model_class = get_model_calss(app_label, model)
    if(query_set == None):
        query_set = model_class.objects.all()
    order_by = request.GET.get('order_by', None)
    if(order_by):
        query_set = query_set.order_by(order_by)

    filter_param = {}
    exclude_param = {}

    for k in request.GET:
        if k.startswith('n'):
            k = k[1:]
            param = exclude_param
        else:
            param = filter_param

        v = None
        if k.startswith('i.'):
            v = int(request.GET[k])
        elif k.startswith('s.'):
            v = request.GET[k]

        if v:
            param[str(k[2:])] = v


    if filter_param :
        query_set = query_set.filter(**filter_param)
    if exclude_param :
        query_set = query_set.exclude(**exclude_param)

    query_dict = QueryDict('', True)
    query_dict.update(request.GET)

    return list_detail.object_list(request, query_set, 30, \
                template_name=select_generic_template_name(app_label, model, 'list'), \
                extra_context={'app_label':app_label,
                               'model':model,
                               'model_class':model_class,
                               'order_by':order_by,
                               'query_dict':query_dict,
                               })

def object_detail(request, app_label, model, object_id, query_set=None):
    if(query_set and not query_set.filter(pk=object_id).exists()):
        messages.warning(request, ugettext('You have no permission on this data.'), fail_silently=True)
        return redirect_to_login(request.path)
    model_class = get_model_calss(app_label, model)
    return list_detail.object_detail(request, model_class.objects.select_related(), object_id, \
                template_name=select_generic_template_name(app_label, model, 'detail'), \
                extra_context={'app_label':app_label, 'model':model, 'model_class':model_class})

@never_cache
def object_create(request, app_label, model, template_name=None,
        template_loader=loader, extra_context=None, post_save_redirect=None,
        login_required=False, context_processors=None, form_class=None, initial=None,
        permission_required=USE_DEFAULT_PERMISSION, force_data=None
        ):
    """
    Generic object-creation function.
    
    Templates: ``<app_label>/<model_name>_form.html``
    Context:
        form
            the form for the object
    """
    if(permission_required == USE_DEFAULT_PERMISSION):
        permission_required = '%s.add_%s' % (app_label, model)
    if(permission_required and not request.user.has_perm(permission_required)):
        messages.warning(request, ugettext('You have no permission to do this.'), fail_silently=True)
        return redirect_to_login(request.path)

    if extra_context is None: extra_context = {}
    if login_required and not request.user.is_authenticated():
        return redirect_to_login(request.path)

    model_class, form_class = create_update.get_model_and_form_class(get_model_calss(app_label, model), form_class)
    if request.method == 'POST':
        if force_data:
            data = {}
            data.update(request.POST)
            data.update(force_data)
        else:
            data = request.POST
        form = form_class(request.POST, request.FILES, prefix=model)
        if form.is_valid():
            new_object = form.save()

            msg = ugettext("The %(verbose_name)s was created successfully.") % \
                                    {"verbose_name": model_class._meta.verbose_name} #IGNORE:W0212
            messages.success(request, msg, fail_silently=True)
            return redirect(post_save_redirect, new_object, app_label, model)
    else:
        d = dict([(k, request.GET[k]) for k in request.GET.keys()])
        d.update(initial or {})
        form = form_class(initial=d, prefix=model)

    # Create the template, context, response
    if template_name:
        t = template_loader.get_template(template_name)
    else:
        t = select_generic_template(app_label, model, 'create')
    c = RequestContext(request, {
        'form': form, 'app_label':app_label, 'model':model, 'model_class':model_class
    }, context_processors)
    create_update.apply_extra_context(extra_context, c)
    return HttpResponse(t.render(c))

@never_cache
def object_update(request, app_label, model, object_id, query_set=None, permission_required=USE_DEFAULT_PERMISSION):
    if(permission_required == USE_DEFAULT_PERMISSION):
        permission_required = '%s.change_%s' % (app_label, model)
    if(permission_required and not request.user.has_perm(permission_required)):
        messages.warning(request, ugettext('You have no permission to do this.'), fail_silently=True)
        return redirect_to_login(request.path)
    if(query_set and not query_set.filter(pk=object_id).exists()):
        messages.warning(request, ugettext('You have no permission on this data.'), fail_silently=True)
        return redirect_to_login(request.path)
    model_class = get_model_calss(app_label, model)
    return create_update.update_object(request, model_class, object_id, \
                post_save_redirect='/%s/%s/%%(id)d/' % (app_label, model),
                template_name=select_generic_template_name(app_label, model, 'edit'), \
                extra_context={'app_label':app_label, 'model':model, 'model_class':model_class})

@never_cache
def object_delete(request, app_label, model, object_id, query_set=None, permission_required=USE_DEFAULT_PERMISSION):
    if(permission_required == USE_DEFAULT_PERMISSION):
        permission_required = '%s.delete_%s' % (app_label, model)
    if(permission_required and not request.user.has_perm(permission_required)):
        messages.warning(request, ugettext('You have no permission to do this.'), fail_silently=True)
        return redirect_to_login(request.path)
    if(query_set and query_set.filter(pk=object_id).exists()):
        messages.warning(request, ugettext('You have no permission on this data.'), fail_silently=True)
        return redirect_to_login(request.path)

    model_class = get_model_calss(app_label, model)
    return create_update.delete_object(request, model_class, '/%s/%s/' % (app_label, model), object_id, \
                template_name=select_generic_template_name(app_label, model, 'confirm_delete'), \
                extra_context={'app_label':app_label, 'model':model, 'model_class':model_class})

